﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using AutoBuild.Core.Framework;

namespace AutoBuild.Core
{
    public class AutoBuildRunner
    {
        private readonly IDirectoryWatcher _watcher;
        readonly IRunnerSelector _runnerSelector;
        private readonly IConsole _console;

        //---------------------------------------------------------
        public AutoBuildRunner(IDirectoryWatcher watcher, IRunnerSelector runnerSelector, IConsole console) 
        {
            _watcher = watcher;
            _runnerSelector = runnerSelector;
            _console = console;

        }

        //---------------------------------------------------------
        public void Start(AutoBuildArguments autoBuildArguments)
        {
            SetPathsAbsolut(autoBuildArguments);
            ValidateCommandLineOptions(autoBuildArguments);

            IBuildRunner runner = GetBuildRunner(autoBuildArguments);
            
            _watcher.FileChanged += (s, e) =>
            {
                _console.Debug("File {0} {1}".With(e.ChangeType, e.Name));
                _watcher.Disable();
                runner.RunBuild(autoBuildArguments);
            };

            runner.BuildCompleted += (s, e) =>
            {
                _watcher.Enable();
            };

            _watcher.Watch(autoBuildArguments.WatchFolder);
            
        }

        //---------------------------------------------------------
        private void SetPathsAbsolut(AutoBuildArguments autoBuildArguments)
        {
            
            if (!autoBuildArguments.BuildFile.IsNullOrWhiteSpace() &&
                !Path.IsPathRooted(autoBuildArguments.BuildFile))
            {
                autoBuildArguments.BuildFile = Path.Combine(Environment.CurrentDirectory, autoBuildArguments.BuildFile);
            }

            if (!autoBuildArguments.WatchFolder.IsNullOrWhiteSpace() &&
                !Path.IsPathRooted(autoBuildArguments.WatchFolder))
            {
                autoBuildArguments.WatchFolder = Path.Combine(Environment.CurrentDirectory,
                                                              autoBuildArguments.WatchFolder);
            }

        }

        //---------------------------------------------------------
        private IBuildRunner GetBuildRunner(AutoBuildArguments autoBuildArguments)
        {
            IBuildRunner runner;
            var runners = _runnerSelector.GetAvailableRunners();
            if (autoBuildArguments.RunnerName.IsNullOrWhiteSpace())
            {
                
                if (runners.Length > 0)
                {
                    runner = runners[0];
                    _console.Info("Warning: No build runner specified. Defaulting to: {0}".With(runner.RunnerName));
                }
                else
                {
                    string message = "Error: No build runner available! Check you configuration!";
                    _console.Error(message);
                    throw new ArgumentException(message);
                }
            }
            else
            {
                runner = _runnerSelector.GetRunner(autoBuildArguments.RunnerName);
                if ( runner == null)
                {
                    var builder = new StringBuilder();
                    builder.AppendLine("Build runner '{0}' was requested, but was not found. Available runners are:");
                    foreach (var buildRunner in runners)
                    {
                        builder.AppendLine(" - " + buildRunner.RunnerName);
                    }
                    string message = builder.ToString().With(autoBuildArguments.RunnerName);
                    _console.Error(message);
                    throw new InvalidOperationException(message);
                }
            }
            _console.Info("Using build runner: {0}".With(runner.RunnerName));
            
            return runner;
        }

        //---------------------------------------------------------
        private void ValidateCommandLineOptions(AutoBuildArguments autoBuildArguments)
        {
            bool hasError = false;
            var errorBuilder = new StringBuilder();

            if (autoBuildArguments.BuildFile.IsNullOrWhiteSpace())
            {
                hasError = true;
                errorBuilder.AppendLine("- Build file was not specified!");
            }
            else if (!File.Exists(autoBuildArguments.BuildFile))
            {
                hasError = true;
                errorBuilder.AppendLine("- Build file '{0}' does not exist or you don't have permission to read it!".With(autoBuildArguments.BuildFile));
            }

            if (!Directory.Exists(autoBuildArguments.WatchFolder))
            {
                hasError = true;
                errorBuilder.AppendLine(
                    "- Watch folder '{0}' does not exist or you don't have permission to read it!".With(
                        autoBuildArguments.WatchFolder));
            }

            if (hasError == true)
            {
                string message = "Cannot execute!{0}The following issues with the configuration where found:{0}{1}".With(
                    Environment.NewLine,
                    errorBuilder.ToString()
                    );

                _console.Error(message);

                throw new InvalidOperationException(message);
            }

        }
    }
}